package main;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;


public class ConnectToGame {
	
	private Socket s = null;
	private boolean connected = false;
	private Choice toSend = null;
	private Controller cont;
	private Sender sender = null;
	private Receiver receiver = null;
	private Object ready = new Object();
	private ObjectInputStream ois = null;
	private ObjectOutputStream oos = null;
		

	public ConnectToGame(InetAddress ip,int port, Controller cont) throws IOException
	{
		this.s = new Socket(ip, port);
		this.cont = cont;
		connected = true;
		sender = new Sender(s);
		sender.start();
		receiver = new Receiver(s);
		receiver.start();
	}
	public ConnectToGame(Socket s, Controller cont)
	{
		this.s = s;
		this.cont = cont;
		connected = true;
		sender = new Sender(s);
		sender.start();
		receiver = new Receiver(s);
		receiver.start();
	}
	
	
	
	/**
	 * Graceful disconnect from socket.
	 */
	public void disconnect()
	{
		connected = false;
		try {
			ois.close();
			oos.close();
			s.close();
		} catch (IOException e) {
		} finally
		{
			try {
				s.close();
			} catch (IOException e) {
			}
		}
		
		
	}
	
	/**
	 * Notifies sender thread about choice to be sent over Socket
	 * @param c Choice to send
	 */
	public void sendChoice(Choice c)
	{
		synchronized (ready)
		{
			toSend = c;
			ready.notify();
		}
		
	}
	
	// Receives opponent choices over Socket
	private class Receiver extends Thread
	{
		private Socket s = null;
		Receiver(Socket s)
		{
			this.s = s;
		}
		public void run()
		{
			Choice choice = null;
			try {
				ois = new ObjectInputStream(new BufferedInputStream(s.getInputStream()));
				while (connected)
				{
						if ((choice = (Choice)ois.readObject()) != null)
						{
							cont.receiveChoice(choice);
						}
				}
				ois.close();
			} catch (Exception e) {
				cont.lostConnectionToOpponent();
			}
	

		}
	
	}
	// Sends choice object over Socket when notified
	private class Sender extends Thread
	{
		private Socket s = null;
		public Sender(Socket s)
		{
			this.s = s;
		}
		public void run()
		{
			
			try {
				oos = new ObjectOutputStream(new BufferedOutputStream(s.getOutputStream()));
				oos.flush();
			
				while(connected)
				{
					
					synchronized(ready)
					{
						ready.wait();
						if (toSend != null)
						{
							oos.writeObject(toSend);
							oos.flush();
							toSend = null;
						}
					}
		
				}
				oos.close();
				
			} catch (IOException e) {
				cont.lostConnectionToOpponent();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}


}
